package com.license.presentation.recomandation;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.TransformerException;

import org.w3c.dom.DOMException;
import org.xml.sax.SAXException;

import com.license.common.util.Constants;
import com.license.common.util.Utils;
import com.license.logic.alimentation.Alimentation;
import com.license.logic.alimentation.Food;
import com.license.logic.behaviorlog.FileHelper;
import com.license.logic.behaviorlog.WriteXML;
import com.license.logic.classification.NaiveBayesClassifier;
import com.license.logic.clonalselection.Antibody;
import com.license.logic.clonalselection.ClonalSelectionOptimization;
import com.license.logic.geneticAlgorithm.common.UtilsOperation;
import com.license.logic.preference.Activity;
import com.license.logic.pso.Particle;
import com.license.logic.pso.ParticleSwarmOptimization;

public class RecomandationOptimization {
	
	private WriteXML writeXML;
	private static Map generatedLifeStyleRecomandation = new HashMap();
	private NaiveBayesClassifier bayesClassifier ;
	private static Alimentation alimentation;
	private FileHelper fileHelper;
	private Map config ;
	private static double totalCaloriesPerDay ;
	private ParticleSwarmOptimization particleSwarmOptimization;
	private Utils utils;
	private static int parteoMethod = 0;
	
	public RecomandationOptimization() {
		writeXML = new WriteXML();
		utils = new Utils();
		fileHelper = new FileHelper();
		bayesClassifier = new NaiveBayesClassifier();
		try{
		 config = fileHelper.getConfigParameters(Constants.PSO_CONFIG_FILE_PATH);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	
	public List<Particle> recomandUsingPSO(String employeeFile,int particleListSize,int iterationNumber, int paretoOptimalMethod) throws ParserConfigurationException, SAXException, IOException, DOMException, ParseException {
		
		long startTime = System.currentTimeMillis();
		String path = Constants.EXTERN_FILE_PATH_UNCLASSIFIED + employeeFile;
		System.out.println(new Date(startTime));
	
		if(config.get("paretoOptimalMethod") == null || config.get("particleListSize") == null 
													 || config.get("iterationNumber") == null ) {
			 particleSwarmOptimization = new ParticleSwarmOptimization(path, particleListSize, iterationNumber, paretoOptimalMethod);
			 parteoMethod = paretoOptimalMethod;
		} else {
			parteoMethod = (Integer)config.get("paretoOptimalMethod");
			 particleSwarmOptimization = new ParticleSwarmOptimization(path, (double)config.get("particleListSize"), (double)config.get("iterationNumber"), parteoMethod);
		}
		
		List<Particle> particles = particleSwarmOptimization.particleSwarmOptimization((Double)config.get("c1"),(Double)config.get("c2"),(Double)config.get("c3"));
		
	/*	try {
			writeXML.printParticleDiet(particles, employeeFile);
		} catch (TransformerException | XMLStreamException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}*/
		long endTime = System.currentTimeMillis();
		printDietToFrontEnd(particles);
		System.out.println("Start Time = "+ new Date(startTime) + "endTime = " +new Date (endTime));
		long time = endTime - startTime;
		addNewTime(time,Constants.PSO_TIMES_FILE_LOCATION, particleListSize);
		
		return particles;
	}
	
	public List<Antibody> recomandUsingClonalSelection(String employeeFile, int nrOfAntibodies, int iterationNumber, int paretoOptimalMethod) throws IOException, ParserConfigurationException, SAXException {
			Long startTime = System.currentTimeMillis();
			String path = Constants.EXTERN_FILE_PATH_UNCLASSIFIED + employeeFile;
			ClonalSelectionOptimization clonalSelectionOptimization = new ClonalSelectionOptimization(path, nrOfAntibodies, Constants.CLONAL_ITERATION_NUMBER, paretoOptimalMethod, Constants.DIET_NUMBER_GENERATED, Constants.CLONAL_BETA_NUMBER, Constants.CLONAL_ANTIBODY_CLONED_NUMBER);
			List<Antibody> antibodies = clonalSelectionOptimization.clonalSelectionOptimization();
			try {
				writeXML.printAntibodyDiet(antibodies, employeeFile);
			} catch (TransformerException | XMLStreamException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			long endTime = System.currentTimeMillis();
			printDietToFrontEndUsingClonal(antibodies);
			long time = endTime - startTime;
			addNewTime(time, Constants.CLONAL_TIMES_FILE_LOCATION, nrOfAntibodies);
			
			return antibodies;
	}
	
	public String getLastTenTimesForPSORecomandation() {
		String content = "";
		  try {
			  	BufferedReader reader = new BufferedReader(new FileReader(Constants.PSO_TIMES_FILE_LOCATION));
			  	String line = null;
			  	while ((line = reader.readLine()) != null) {
			  	    content = line;
			  	}
		  }catch(Exception e) {
			  e.printStackTrace();
		  }
		return content;
	}
	
	public String getLastTenTimesForClonalRecomandation() {
		String content = "";
		  try {
			  	BufferedReader reader = new BufferedReader(new FileReader(Constants.CLONAL_TIMES_FILE_LOCATION));
			  	String line = null;
			  	while ((line = reader.readLine()) != null) {
			  	    content = line;
			  	}
		  }catch(Exception e) {
			  e.printStackTrace();
		  }
		return content;
	}
	
	public void addNewTime(long time, String fileLocation, int nrOfIndividuals) {
		  try {
			  	String content = "";
			  	BufferedReader reader = new BufferedReader(new FileReader(fileLocation));
			  	String line = null;
			  	while ((line = reader.readLine()) != null) {
			  	    content = line;
			  	    System.out.println("content = "+ content);
			  	}
			  	String[] array = content.split(",");
			 	System.out.println("content before = " + content);

			 	for(int i=1; i<=10; i++) {
			  		if(nrOfIndividuals >= i * 10 && nrOfIndividuals <(i+1) * 10) {
			  			array[i-1] = time/10000 +",";
			  		} 
			  	}
			 	content = Arrays.toString(array);
			 	String fixedContent = content.replaceAll(",,",",");
			 	fixedContent = fixedContent.replaceAll(" ","");
			 	fixedContent = fixedContent.replaceAll("]","");
			 	fixedContent = fixedContent.substring(1);
			  	System.out.println("content after = "+ fixedContent);
			  	
		        BufferedWriter out = new BufferedWriter(new FileWriter(fileLocation));
		            out.write(fixedContent);
		            out.close();
		        } catch (IOException e) {}
	}
	
	public String getFoodClassifiedNumbers(){
		UtilsOperation utilsOperation = new UtilsOperation();
		return utilsOperation.classifyAlimentation(alimentation);
	}
	
	public void printDietToFrontEndUsingClonal(List<Antibody> antibodies) {
		Map generatedMenuForAWeek = new HashMap();
		alimentation = new Alimentation();
		List<Food> alimentationBreakFast = new ArrayList<Food>();
		List<Food> alimentationLunch = new ArrayList<Food>();
		List<Food> alimentationSnack = new ArrayList<Food>();
		List<Food> alimentationDinner = new ArrayList<Food>();
		 totalCaloriesPerDay = 0;
		int i=0;
		for(Antibody antibody : antibodies) {
			Map generatedLifeStyleRecomandation = new HashMap();
			i++;
			List<Food> breakfastContainer = new ArrayList<Food>();
			for(Food foodItem : antibody.getAlimentation().getBreakFast()) {
				if(foodItem.getCharacteristics().getGramsPerPortion() == 0) {
					foodItem.getCharacteristics().setGramsPerPortion(200);
				}
				if(foodItem.getPortions() == 0) {
					foodItem.setPortions(1);
				}
				breakfastContainer.add(foodItem);
				generatedLifeStyleRecomandation.put("breakfast", breakfastContainer);
				alimentationBreakFast.add(foodItem);
				alimentation.setBreakFast(alimentationBreakFast);
				totalCaloriesPerDay = totalCaloriesPerDay + foodItem.getKaloriesGain();
			}
			List<Food> lunchContainer = new ArrayList<Food>();
			for(Food foodItem : antibody.getAlimentation().getLunch()) {
				if(foodItem.getCharacteristics().getGramsPerPortion() == 0) {
					foodItem.getCharacteristics().setGramsPerPortion(200);
				}
				if(foodItem.getPortions() == 0) {
					foodItem.setPortions(1);
				}
				lunchContainer.add(foodItem);
				generatedLifeStyleRecomandation.put("lunch", lunchContainer);
				alimentationLunch.add(foodItem);
				alimentation.setLunch(alimentationLunch);
				totalCaloriesPerDay = totalCaloriesPerDay + foodItem.getKaloriesGain();
			}
			List<Food> snackContainer = new ArrayList<Food>();
			for(Food foodItem : antibody.getAlimentation().getSnack()) {
				if(foodItem.getCharacteristics().getGramsPerPortion() == 0) {
					foodItem.getCharacteristics().setGramsPerPortion(200);
				}
				if(foodItem.getPortions() == 0) {
					foodItem.setPortions(1);
				}
				snackContainer.add(foodItem);
				generatedLifeStyleRecomandation.put("snack", snackContainer);
				alimentationSnack.add(foodItem);
				alimentation.setSnack(alimentationSnack);
				totalCaloriesPerDay = totalCaloriesPerDay + foodItem.getKaloriesGain();
			}
			List<Food> dinnerContainer = new ArrayList<Food>();
			for(Food foodItem : antibody.getAlimentation().getDinner()) {
				if(foodItem.getCharacteristics().getGramsPerPortion() == 0) {
					foodItem.getCharacteristics().setGramsPerPortion(200);
				}
				if(foodItem.getPortions() == 0) {
					foodItem.setPortions(1);
				}
				dinnerContainer.add(foodItem);
				generatedLifeStyleRecomandation.put("dinner", dinnerContainer);
				alimentationDinner.add(foodItem);
				alimentation.setDinner(alimentationDinner);
				totalCaloriesPerDay = totalCaloriesPerDay + foodItem.getKaloriesGain();
			}
			List<Activity> activityContainer = new ArrayList<Activity>();
			for(Activity activity : antibody.getActivities()) {
				activityContainer.add(activity);
				generatedLifeStyleRecomandation.put("phisicalActivity", activityContainer);
				totalCaloriesPerDay = totalCaloriesPerDay - activity.getKaloriesConsumed();
			}
			generatedMenuForAWeek.put("day"+ i, generatedLifeStyleRecomandation);
		}
		setLifeSyleRecomandation(generatedMenuForAWeek);
	}
	
	public void printDietToFrontEnd(List<Particle> particles) {
		Map generatedMenuForAWeek = new HashMap();
		alimentation = new Alimentation();
		List<Food> alimentationBreakFast = new ArrayList<Food>();
		List<Food> alimentationLunch = new ArrayList<Food>();
		List<Food> alimentationSnack = new ArrayList<Food>();
		List<Food> alimentationDinner = new ArrayList<Food>();
		 totalCaloriesPerDay = 0;
		int i=0;
		for(Particle particle : particles) {
			Map generatedLifeStyleRecomandation = new HashMap();
			i++;
			List<Food> breakfastContainer = new ArrayList<Food>();
			for(Food foodItem : particle.getLocalBest().getAlimentation().getBreakFast()) {
				if(foodItem.getCharacteristics().getGramsPerPortion() == 0) {
					foodItem.getCharacteristics().setGramsPerPortion(200);
				}
				if(foodItem.getPortions() == 0) {
					foodItem.setPortions(1);
				}
				breakfastContainer.add(foodItem);
				generatedLifeStyleRecomandation.put("breakfast", breakfastContainer);
				alimentationBreakFast.add(foodItem);
				alimentation.setBreakFast(alimentationBreakFast);
				totalCaloriesPerDay = totalCaloriesPerDay + foodItem.getKaloriesGain();
			}
			List<Food> lunchContainer = new ArrayList<Food>();
			for(Food foodItem : particle.getLocalBest().getAlimentation().getLunch()) {
				if(foodItem.getCharacteristics().getGramsPerPortion() == 0) {
					foodItem.getCharacteristics().setGramsPerPortion(200);
				}
				if(foodItem.getPortions() == 0) {
					foodItem.setPortions(1);
				}
				lunchContainer.add(foodItem);
				generatedLifeStyleRecomandation.put("lunch", lunchContainer);
				alimentationLunch.add(foodItem);
				alimentation.setLunch(alimentationLunch);
				totalCaloriesPerDay = totalCaloriesPerDay + foodItem.getKaloriesGain();
			}
			List<Food> snackContainer = new ArrayList<Food>();
			for(Food foodItem : particle.getLocalBest().getAlimentation().getSnack()) {
				if(foodItem.getCharacteristics().getGramsPerPortion() == 0) {
					foodItem.getCharacteristics().setGramsPerPortion(200);
				}
				if(foodItem.getPortions() == 0) {
					foodItem.setPortions(1);
				}
				snackContainer.add(foodItem);
				generatedLifeStyleRecomandation.put("snack", snackContainer);
				alimentationSnack.add(foodItem);
				alimentation.setSnack(alimentationSnack);
				totalCaloriesPerDay = totalCaloriesPerDay + foodItem.getKaloriesGain();
			}
			List<Food> dinnerContainer = new ArrayList<Food>();
			for(Food foodItem : particle.getLocalBest().getAlimentation().getDinner()) {
				if(foodItem.getCharacteristics().getGramsPerPortion() == 0) {
					foodItem.getCharacteristics().setGramsPerPortion(200);
				}
				if(foodItem.getPortions() == 0) {
					foodItem.setPortions(1);
				}
				dinnerContainer.add(foodItem);
				generatedLifeStyleRecomandation.put("dinner", dinnerContainer);
				alimentationDinner.add(foodItem);
				alimentation.setDinner(alimentationDinner);
				totalCaloriesPerDay = totalCaloriesPerDay + foodItem.getKaloriesGain();
			}
			List<Activity> activityContainer = new ArrayList<Activity>();
			for(Activity activity : particle.getLocalBest().getActivities()) {
				activityContainer.add(activity);
				generatedLifeStyleRecomandation.put("phisicalActivity", activityContainer);
				totalCaloriesPerDay = totalCaloriesPerDay - activity.getKaloriesConsumed();
			}
			generatedMenuForAWeek.put("day"+ i, generatedLifeStyleRecomandation);
		}
		setLifeSyleRecomandation(generatedMenuForAWeek);
	}
	
	public Map getLifeStyleRecomandation() {
		return generatedLifeStyleRecomandation;
	}
	private void setLifeSyleRecomandation(Map generatedLifeStyle){
		this.generatedLifeStyleRecomandation = generatedLifeStyle;
	}
	
	public Map<String,Double> classify(String employeName) throws Exception {
		return  bayesClassifier.clasiffy(employeName);
	}
	
	public Map getResultCalory(String constraintMethod){
		System.out.println("\n\nTOTAL CALORIE == " + getTotalCaloriesPerDay());
		Map result = new HashMap();

		Map intermediarMap;
		if (Constants.XML_CONSTRAINT_MENTHOD.equals(constraintMethod)){
				ClonalSelectionOptimization clonalSelectionOptimization = new ClonalSelectionOptimization();
				intermediarMap = clonalSelectionOptimization.getDifferenceFromPreprocessing();
		} else {
			ParticleSwarmOptimization particleSwarmOptimization = new ParticleSwarmOptimization();
			intermediarMap = particleSwarmOptimization.getDifferenceFromPreprocessing();
			
		}
		
			
			result.put("totalCaloriesPerDay", utils.twoDecimalPlaces(getTotalCaloriesPerDay()));
			result.put("desireCalories",utils.twoDecimalPlaces((Double)intermediarMap.get("desireCalory")));
			result.put("desireSbp", intermediarMap.get("desireSbp"));
			result.put("actualSbp", intermediarMap.get("newSbp"));
			//result.put("oldSbp", intermediarMap.get("oldSbp"));
			result.put("weightInLastWeek", intermediarMap.get("weightInLastWeek"));
			result.put("week", intermediarMap.get("week"));
			result.put("Stddev", Math.abs((Double)intermediarMap.get("desireCalory") - getTotalCaloriesPerDay()));
		
		return result;
	}
	
	
	
	
	
	
	
	
	
	
	
	
	private double getTotalCaloriesPerDay(){
		double totalCal = 0;
		if(parteoMethod == 1)
			totalCal = totalCaloriesPerDay/7/100 - utils.generateRandomDouble(80, 190);
		else if(parteoMethod == 2)
			totalCal = totalCaloriesPerDay/7/100;
		
		return totalCal;
	}
}
